home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
APPLICAT
/
C050.ZIP
/
SFSSRC.ZIP
/
SFS.SRC
/
AS
/
AS_ORBIT.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-04
|
10KB
|
365 lines
/****************************************************************
as_orbit.c Orbital calculation routines
for astronomy (as) subsystem
Copyright (c) 1991, Ted A. Campbell
Bywater Software
P. O. Box 4023
Duke Station
Durham, NC 27706
email: tcamp@hercules.acpub.duke.edu
Copyright and Permissions Information:
All U.S. and international copyrights are claimed by the
author. The author grants permission to use this code
and software based on it under the following conditions:
(a) in general, the code and software based upon it may be
used by individuals and by non-profit organizations; (b) it
may also be utilized by governmental agencies in any country,
with the exception of military agencies; (c) the code and/or
software based upon it may not be sold for a profit without
an explicit and specific permission from the author, except
that a minimal fee may be charged for media on which it is
copied, and for copying and handling; (d) the code must be
distributed in the form in which it has been released by the
author; and (e) the code and software based upon it may not
be used for illegal activities.
****************************************************************/
#include "math.h"
#include "time.h"
#include "bw.h"
#include "as.h"
#define KEP_ACCURACY 0.00001
/****************************************************************
or_init() Set up an orbit
****************************************************************/
or_init( orbit, ap, aa )
struct as_orbit *orbit;
double aa, ap;
{
#ifdef DEBUG
if ( orbit->focus->radius <= 0.0 )
{
sprintf( bw_ebuf, "[pr:] or_init() received orbit->focus->radius = %lf",
orbit->focus->radius );
bw_error( bw_ebuf );
return;
}
if ( orbit->focus->sid_day < 0.0 )
{
sprintf( bw_ebuf, "[pr:] or_init() received orbit->focus->sid_day = %lf",
orbit->focus->sid_day );
bw_error( bw_ebuf );
return;
}
if ( orbit->focus->mass < 0.0 )
{
sprintf( bw_ebuf, "[pr:] or_init() received orbit->focus->mass = %lf",
orbit->focus->mass );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->inclination > 180.0 ) || ( orbit->inclination < -180.0 ))
{
sprintf( bw_ebuf, "[pr:] or_init() received orbit->inclination = %lf",
orbit->inclination );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->lon_an > 180.0 ) || ( orbit->lon_an < -180.0 ))
{
sprintf( bw_ebuf, "[pr:] or_init() received orbit->lon_an = %lf",
orbit->lon_an );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->arg_per > 180.0 ) || ( orbit->arg_per < -180.0 ))
{
sprintf( bw_ebuf, "[pr:] or_init() received orbit->arg_per = %lf",
orbit->arg_per );
bw_error( bw_ebuf );
return;
}
#endif
/*** Calculate semimajor axis */
orbit->semimajor = ( aa + ap + ( 2 * orbit->focus->radius )) / 2;
/*** Calculate orbital center - focus distance */
orbit->dist = orbit->semimajor - ( orbit->focus->radius + ap );
/*** Calculate semiminor axis */
orbit->semiminor = sqrt( (double) ( orbit->semimajor * orbit->semimajor ) - (double) ( orbit->dist * orbit->dist ));
/*** Calculate orbital eccentricity */
orbit->eccentricity = sqrt( 1.0 - (( orbit->semiminor / (double) orbit->semimajor ) * ( orbit->semiminor / (double) orbit->semimajor )) );
/*** Calculate orbital period */
orbit->period = sqrt ( ( ( 4.0 * ( PI * (double) PI ) ) / ( UGC * orbit->focus->mass ) )
* ( orbit->semimajor * orbit->semimajor * orbit->semimajor ) );
/*** Calculate the increment factor of longitude of
the ascending node. This factor must be multiplied
by a time factor (orbital period or time into orbit,
in seconds). See Davidoff, pp. 8-9 and 8-10, and
formula 8.14. */
if ( orbit->focus->sid_day == 0.0 )
{
orbit->lif = 0;
}
else
{
orbit->lif = (2 * PI) / (double) orbit->focus->sid_day;
}
}
/****************************************************************
or_kep() Solve Kepler's equation
Globals utilized:
orbit->eccentricity Eccentricity of the orbital ellipse
orbit->semimajor Semimajor axis of the orbital ellipse (km)
orbit->period Orbital period (seconds)
Input:
t Time from periapsis in seconds
( 0 < t < orbit->period )
Output:
theta Angle between periapsis, geocenter, and
current position (theta).
r Distance from satellite to focal center,
in kilometers
****************************************************************/
or_kep( orbit, t, theta, r )
struct as_orbit *orbit;
long t;
double *theta;
long *r;
{
double z, z3, E;
z = 2.0 * PI * ( (double) t / (double) orbit->period );
E = z;
do
{
z3 = ( E - ( orbit->eccentricity * sin( E )) - z ) / ( 1 - ( orbit->eccentricity * cos( E )));
E = E - z3;
}
while ( fabs( z3 ) > KEP_ACCURACY );
*theta = PI;
if ( E != PI )
{
*theta = 2.0 * atan( sqrt( ( 1 - orbit->eccentricity ) / ( 1 + orbit->eccentricity )) * tan( E / 2.0 ));
if ( E > PI )
{
*theta = ( (double) 2.0 * PI ) + *theta;
}
}
*r = orbit->semimajor * ( 1 - orbit->eccentricity * orbit->eccentricity ) / ( 1 + orbit->eccentricity * cos( *theta ));
return 1;
}
/****************************************************************
or_ssp() Calculate Subsatellite Point
This function utilizes available data on the satellite
to return the subsatellite point, that is, the point
on the surface of the orbital focus directly under
the satellite at a given moment.
****************************************************************/
or_ssp( orbit, t, latitude, longitude, r, n )
struct as_orbit *orbit;
long t, *r, *n;
double *longitude, *latitude;
{
static long _r, tp;
static double theta;
double n1, n2, n4, E, lan;
long t1;
#ifdef DEBUG
if ( orbit->focus->radius < OR_RAD_MIN )
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->focus->radius = %lf",
orbit->focus->radius );
bw_error( bw_ebuf );
return;
}
if ( orbit->focus->sid_day < OR_SID_MIN )
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->focus->sid_day = %lf",
orbit->focus->sid_day );
bw_error( bw_ebuf );
return;
}
if ( orbit->focus->mass < OR_MAS_MIN )
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->focus->mass = %le",
orbit->focus->mass );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->inclination > OR_INC_MAX ) || ( orbit->inclination < OR_INC_MIN ))
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->inclination = %lf",
orbit->inclination );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->lon_an > OR_LAN_MAX ) || ( orbit->lon_an < OR_LAN_MIN ))
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->lon_an = %lf",
orbit->lon_an );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->arg_per > OR_ARP_MAX ) || ( orbit->arg_per < OR_ARP_MIN ))
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->arg_per = %lf",
orbit->arg_per );
bw_error( bw_ebuf );
return;
}
if ( orbit->period < OR_PER_MIN )
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->period = %lf",
orbit->period );
bw_error( bw_ebuf );
return;
}
if ( ( orbit->eccentricity < OR_ECC_MIN ) || ( orbit->eccentricity > OR_ECC_MAX ))
{
sprintf( bw_ebuf, "[pr:] or_ssp() received orbit->eccentricity = %lf",
orbit->eccentricity );
bw_error( bw_ebuf );
return;
}
#endif
*n = t / (long) orbit->period; /* return number of current orbit */
t1 = t - ( orbit->period * ( *n ) ); /* get seconds into this orbit */
if ( t1 == 0 )
{
t1 = 1;
}
or_kep( orbit, t1, &theta, &_r );
*r = _r;
#ifdef OLD_DEBUG
sprintf( bw_ebuf, "or_ssp(): r = %ld (%ld) ", _r, *r );
bw_debug( bw_ebuf );
sprintf( bw_ebuf, "or_ssp(): theta = %lf", theta );
bw_debug( bw_ebuf );
#endif
/*** Calculate the longitude of the ascending node at
the beginning of this orbit. See Davidoff, p. 8-9
and 8-10, and equations 8.13a, 8.13b, and 8.14. */
lan = ( orbit->lon_an * DEG_RAD ) - ( orbit->lif * orbit->period * *n );
/*** Calculate the latitude of the SSP. See Davidoff,
pp. 8-13 - 8-15, esp. equation 8.20. */
*latitude = asin( sin( orbit->inclination * DEG_RAD )
* sin( theta + ( orbit->arg_per * DEG_RAD )));
if ( ( orbit->inclination >= 0 ) && ( orbit->inclination < 90 ) )
{
n2 = 1;
}
else
{
n2 = 0;
}
if ( ( ( *latitude ) * RAD_DEG ) < 0.0 )
{
n4 = 1;
}
else
{
n4 = 0;
}
if ( ( orbit->arg_per > 180 ) && ( orbit->arg_per <= 540 ) )
{
n1 = 1;
}
else
{
n1 = 0;
}
E = 2 * atan( (double) pow( ( 1 - orbit->eccentricity ) / ( 1 + orbit->eccentricity ), (double) 0.5 )
* tan( ( orbit->arg_per * DEG_RAD ) / 2.0 )) + ( 2.0 * PI * n1);
tp = ( orbit->period / ( 2.0 * PI ) ) * ( E - sin( E ) );
*longitude = as_lfix( lan
- pow( (double) -1.0, n2 + n4 )
* acos( cos( theta + ( orbit->arg_per * DEG_RAD ))
/ cos( *latitude ) )
- orbit->lif * (double) t1
- orbit->lif * (double) tp );
/* convert to degrees */
*longitude = *longitude * RAD_DEG;
*latitude = *latitude * RAD_DEG;
}
double
as_lfix( l )
double l;
{
double l1;
l1 = l;
while ( l1 < ( 0 - PI ) )
{
l1 += ( 2.0 * PI );
}
while ( l1 > PI )
{
l1 -= ( 2.0 * PI );
}
return l1;
}